              package com.java.diagnostics.visualizer.impl.logging;
              
              import java.io.PrintWriter;
              import java.io.StringWriter;
              import java.util.Date;
              import java.util.logging.Formatter;
              import java.util.logging.LogRecord;
              
              public class EntryAndExitFormatter extends Formatter
              {
                private static final String EXIT_ARROW = " < ";
                private static final String MS = " ms";
                private static final String ENTRY_ARROW = " > ";
                private static final String PLUS = " + ";
                private static final String SPACE = " ";
                private static final String TAB = "     ";
                private static final String CLOSE_BRACKET = "] ";
                private static final String OPEN_BRACKET = " [";
                private static final String FOUND_EXCEPTION = "Found exception: ";
                private static final String NEWLINE = System.getProperty("line.separator");
                private static final String EXIT = "RETURN";
                private static final String ENTRY = "ENTRY";
                private static final int deltaLength = 12;
                private final long[] timingStack = new long[100];
              
                private int timingIndex = 0;
              
                public String format(LogRecord record)
                {
                  StringBuffer buffer = new StringBuffer();
                  String message = record.getMessage();
                  if ("ENTRY".equals(message)) {
                    this.timingIndex = ((this.timingIndex + 1) % this.timingStack.length);
                    long millis = record.getMillis();
                    this.timingStack[this.timingIndex] = millis;
                    appendDate(buffer, millis);
                    for (int i = 0; i < this.timingIndex; i++) {
                      buffer.append("     ");
                    }
              
                    for (int i = 0; i < 12; i++) {
                      buffer.append(" ");
                    }
                    buffer.append(" > ");
                    appendMethod(record, buffer);
                  } else if ("RETURN".equals(message)) {
                    long millis = record.getMillis();
                    appendDate(buffer, millis);
                    for (int i = 0; i < this.timingIndex; i++) {
                      buffer.append("     ");
                    }
                    buffer.append(" + ");
                    long delta = millis - this.timingStack[this.timingIndex];
                    String deltaString = new Double(delta).toString();
                    buffer.append(deltaString);
                    buffer.append(" ms");
              
                    for (int i = deltaString.length() + 6; i < 12; i++) {
                      buffer.append(" ");
                    }
                    buffer.append(" < ");
              
                    appendMethod(record, buffer);
                    this.timingIndex = ((this.timingIndex - 1) % this.timingStack.length);
                  } else {
                    long millis = record.getMillis();
                    appendDate(buffer, millis);
                    buffer.append("     ");
                    buffer.append(record.getLevel());
                    buffer.append("     ");
                    buffer.append(message);
                  }
              
                  Throwable ex = record.getThrown();
                  while (ex != null) {
                    buffer.append("Found exception: ");
                    buffer.append(ex.getMessage());
                    buffer.append(NEWLINE);
                    buffer.append(getStackTraceAsString(ex));
                    ex = ex.getCause();
                  }
                  buffer.append(NEWLINE);
                  return buffer.toString();
                }
              
                private void appendDate(StringBuffer buffer, long millis)
                {
                  buffer.append(" [");
                  buffer.append(new Date(millis));
                  buffer.append("] ");
                }
              
                private void appendMethod(LogRecord record, StringBuffer buffer)
                {
                  buffer.append(record.getSourceClassName());
                  buffer.append(".");
                  buffer.append(record.getSourceMethodName());
                  buffer.append("()");
                }
              
                private String getStackTraceAsString(Throwable exception)
                {
                  StringWriter sw = new StringWriter();
                  exception.printStackTrace(new PrintWriter(sw, true));
                  return sw.toString();
                }
              }

